<script lang="ts">
	// Slots:
	/**
	 * @slot {{}} lead - Allows for an optional leading element, such as an icon.
	 * @slot {{}} summary - Provide the interactive summary of each item.
	 * @slot {{}} content - Provide the content of each item.
	 * @slot {{}} iconClosed - Allows for an optional element when the AccordionItem is closed, such as an icon
	 * @slot {{}} iconOpen - Allows for an optional element when the AccordionItem is open, such as an icon
	 */
	// Events:
	// FORWARDED: do not document these, breaks the type definition
	// DISPATCHED: document directly above the definition, like props (ex: paginator)

	import { createEventDispatcher, getContext } from 'svelte';
	import type { Writable } from 'svelte/store';
	import { dynamicTransition } from '../../internal/transitions.js';
	import type { CssClasses, SvelteEvent, Transition, TransitionParams } from '../../index.js';

	// Types
	type TransitionIn = $$Generic<Transition>;
	type TransitionOut = $$Generic<Transition>;
	type AccordionItemEvent = {
		toggle: { event?: Event; id: string; panelId: string; open: boolean; autocollapse: boolean };
	};

	// Event Dispatcher
	const dispatch = createEventDispatcher<AccordionItemEvent>();

	// Props (state)
	/** Set open by default on load. */
	export let open = false;
	// Props (a11y)
	/**
	 * Provide a unique input id. Auto-generated by default
	 * @type {string}
	 */
	export let id = String(Math.random());

	// Classes
	const cBase = '';
	const cControl = 'text-start w-full flex items-center space-x-4';
	const cControlIcons = 'fill-current w-3 transition-transform duration-[200ms]';
	const cPanel = '';

	// Context API
	/** Set the auto-collapse mode. */
	export let autocollapse: boolean = getContext('autocollapse');
	/** The writable store that houses the auto-collapse active item UUID. */
	export let active: Writable<string | null> = getContext('active');

	// ---
	/** Set the disabled state for this item. */
	export let disabled: boolean = getContext('disabled');
	/** Provide classes to set the accordion item padding styles. */
	export let padding: CssClasses = getContext('padding');
	/** Provide classes to set the accordion item hover styles. */
	export let hover: CssClasses = getContext('hover');
	/** Provide classes to set the accordion item rounded styles. */
	export let rounded: CssClasses = getContext('rounded');
	// ---
	/** Provide arbitrary classes to the trigger button region. */
	export let caretOpen: CssClasses = getContext('caretOpen');
	/** Provide arbitrary classes to content panel region. */
	export let caretClosed: CssClasses = getContext('caretClosed');
	// ---
	/** Provide arbitrary classes to the trigger button region. */
	export let regionControl: CssClasses = getContext('regionControl');
	/** Provide arbitrary classes to content panel region. */
	export let regionPanel: CssClasses = getContext('regionPanel');
	// FIXME: this will need to be renamed `regionIcons` in the future
	/** Provide arbitrary classes default region. */
	export let regionCaret: CssClasses = getContext('regionCaret');

	// Props (transitions)
	/** Enable/Disable transitions */
	export let transitions: boolean = getContext('transitions');
	/**
	 * Provide the transition to used on entry.
	 * @type {TransitionIn}
	 */
	export let transitionIn: TransitionIn = getContext('transitionIn');
	/**
	 * Transition params provided to `transitionIn`.
	 * @type {TransitionParams}
	 */
	export let transitionInParams: TransitionParams<TransitionIn> = getContext('transitionInParams');
	/**
	 * Provide the transition to used on exit.
	 * @type {TransitionOut}
	 */
	export let transitionOut: TransitionOut = getContext('transitionOut');
	/**
	 * Transition params provided to `transitionOut`.
	 * @type {TransitionParams}
	 */
	export let transitionOutParams: TransitionParams<TransitionOut> = getContext('transitionOutParams');

	const svgCaretIcon = `
		<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
			<path d="M201.4 374.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 306.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z" />
		</svg>`;

	// Change open behavior based on auto-collapse mode
	function setActive(event?: SvelteEvent<MouseEvent, HTMLButtonElement>): void {
		if (autocollapse === true) {
			// Set item active
			active.set(id);
		} else {
			// Toggle Item on click
			open = !open;
		}
		// Always fire the toggle event
		onToggle(event);
	}

	function onToggle(event?: SvelteEvent<MouseEvent, HTMLButtonElement>): void {
		const currentOpenState = autocollapse ? $active === id : open;
		/** @event {{ event: Event, id: string, panelId: string, open: boolean, autocollapse: boolean }} toggle - Fires when an accordion item is toggled. */
		dispatch('toggle', {
			event,
			id,
			panelId: `accordion-panel-${id}`,
			open: currentOpenState,
			autocollapse
		});
	}

	// If auto-collapse mode enabled and item is set open, set as this item active
	if (autocollapse && open) setActive();

	// Reactive State
	$: if (open && autocollapse) setActive();
	$: openState = autocollapse ? $active === id : open;
	// Reactive Classes
	$: classesBase = `${cBase} ${$$props.class ?? ''}`;
	$: classesControl = `${cControl} ${padding} ${hover} ${rounded} ${regionControl}`;
	$: classesCaretState = openState ? caretOpen : caretClosed;
	$: classesControlCaret = `${cControlIcons} ${regionCaret} ${classesCaretState}`;
	$: classesControlIcons = `${cControlIcons} ${regionCaret}`;
	$: classesPanel = `${cPanel} ${padding} ${rounded} ${regionPanel}`;
</script>

<!-- @component The Accordion child element. -->

<div class="accordion-item {classesBase}" data-testid="accordion-item">
	<!-- Control -->
	<button
		type="button"
		class="accordion-control {classesControl}"
		{id}
		on:click={setActive}
		on:click
		on:keydown
		on:keyup
		on:keypress
		aria-expanded={openState}
		aria-controls="accordion-panel-{id}"
		{disabled}
	>
		<!-- Lead -->
		{#if $$slots.lead}
			<div class="accordion-lead">
				<slot name="lead" />
			</div>
		{/if}
		<!-- Summary -->
		<div class="accordion-summary flex-1">
			<slot name="summary">(summary)</slot>
		</div>
		<!-- Icons -->
		{#if $$slots.iconClosed || $$slots.iconOpen}
			<!-- Custom -->
			<!-- If a custom icon is provided, do not use rotation -->
			<div class="accordion-summary-icons {classesControlIcons}">
				{#if openState}
					<slot name="iconClosed">{@html svgCaretIcon}</slot>
				{:else}
					<slot name="iconOpen">{@html svgCaretIcon}</slot>
				{/if}
			</div>
		{:else}
			<!-- SVG Caret -->
			<div class="accordion-summary-caret {classesControlCaret}">{@html svgCaretIcon}</div>
		{/if}
	</button>
	<!-- Panel -->
	{#if openState}
		<div
			class="accordion-panel {classesPanel}"
			id="accordion-panel-{id}"
			in:dynamicTransition|local={{ transition: transitionIn, params: transitionInParams, enabled: transitions }}
			out:dynamicTransition|local={{ transition: transitionOut, params: transitionOutParams, enabled: transitions }}
			role="region"
			aria-hidden={!openState}
			aria-labelledby={id}
		>
			<slot name="content">(content)</slot>
		</div>
	{/if}
</div>
